#include "catalog.h"
#include "query.h"
#include "index.h"
#include <cstring>

/*
 * Selects records from the specified relation.
 *
 * Returns:
 * 	OK on success
 * 	an error code otherwise
 */
Status Operators::Select(const string & result,      // name of the output relation
	                 const int projCnt,          // number of attributes in the projection
		         const attrInfo projNames[], // the list of projection attributes
		         const attrInfo *attr,       // attribute used inthe selection predicate 
		         const Operator op,         // predicate operation
		         const void *attrValue)     // literal value in the predicate
{

    AttrDesc attrDesc;
    AttrDesc * pAttrDesc;
    RelDesc relDesc;
    int recLen = 0;
    Status status;
    string newRel(result);
    AttrDesc * projDesc = new AttrDesc[projCnt];
 
    strcpy(relDesc.relName, result.c_str());
    relDesc.attrCnt = projCnt;
    relDesc.indexCnt = 0;

    //Get description and calculate length of result tuple
    for(int i = 0; i < projCnt; i++)
    {
       status = attrCat->getInfo(string(projNames[i].relName), string(projNames[i].attrName), attrDesc);

       	if(status != OK)
	{
	    delete[] projDesc;
       	    return status;
	}

	strcpy(projDesc[i].relName, attrDesc.relName);
	strcpy(projDesc[i].attrName, attrDesc.attrName);
	projDesc[i].attrOffset = recLen;
	projDesc[i].attrType = attrDesc.attrType;
	projDesc[i].attrLen = attrDesc.attrLen;
	projDesc[i].indexed = 0;

	if(status != 0)
	{
	    delete[] projDesc;
	    return status;
	}

	recLen += attrDesc.attrLen;
    }

    //Get description of attribute used in the predicate
    if(attr)
    {
    	status = attrCat->getInfo(string(attr->relName), string(attr->attrName), attrDesc);

    	if(status != OK)
    	{
            delete[] projDesc;
    	    return status;
        }

	pAttrDesc = &attrDesc;
    }
    else
    {
        pAttrDesc = NULL;
    }

    //Either call index select or scan select based on the predicate
    if(op == EQ && attrDesc.indexed)
    {

        status = IndexSelect(result,      // name of the output relation
                             projCnt,     // number of attributes in the projection
                             projDesc, // The projection list (as AttrDesc)
                             pAttrDesc,   // the attribute in the selection predicate
                             op,          // the predicate operation
                             attrValue,   // a pointer to the literal value in the predicate
                             recLen);     // length of a tuple in the result relation
    }
    else
    {
        status = ScanSelect(result,      // name of the output relation
                            projCnt,     // number of attributes in the projection
                            projDesc, // The projection list (as AttrDesc)
                            pAttrDesc,   // the attribute in the selection predicate
                            op,          // the predicate operation
                            attrValue,   // a pointer to the literal value in the predicate
                            recLen);     // length of a tuple in the result relation
    }

    delete[] projDesc;

    if(status != OK)
        return status;

    return OK;
}

